/**
 *  Copyright 2013 University Pierre & Marie Curie - UMR CNRS 7606 (LIP6/MoVe)
 *  All rights reserved.   This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *  Initial contributor:
 *    Lom M. Hillah - <lom-messan.hillah@lip6.fr>
 *
 *  Mailing list:
 *    lom-messan.hillah@lip6.fr
 */
package fr.lip6.msr4j.datamodel.nodes;

import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.frames.Adjacency;
import com.tinkerpop.frames.Property;
import com.tinkerpop.frames.VertexFrame;
import com.tinkerpop.frames.annotations.gremlin.GremlinGroovy;

import fr.lip6.msr4j.datamodel.relations.AddRelation;
import fr.lip6.msr4j.datamodel.relations.CoCommitterRelation;
import fr.lip6.msr4j.datamodel.relations.ForkRelation;
import fr.lip6.msr4j.datamodel.relations.HoldAdminRoleRelation;
import fr.lip6.msr4j.datamodel.relations.InvolveRelation;
import fr.lip6.msr4j.datamodel.relations.ModifyRelation;
import fr.lip6.msr4j.datamodel.relations.PropagateRelation;
import fr.lip6.msr4j.datamodel.relations.RegisteredInRelation;
import fr.lip6.msr4j.datamodel.relations.ReplaceRelation;
import fr.lip6.msr4j.datamodel.relations.SameProjectAsRelation;
import fr.lip6.msr4j.datamodel.relations.TouchRelation;

/**
 * Basic Domain Concept of Committer.
 * 
 * @author lom
 * 
 */
public interface Committer extends VertexFrame {

	@Property("id")
	void setId(String id);

	@Property("id")
	String getId();

	@Property("name")
	void setName(String name);

	@Property("name")
	String getName();

	@Property("email")
	void setEmail(String email);

	@Property("email")
	String getEmail();

	@Property("perso-web-page")
	void setPersoWebPage(String pswb);

	@Property("perso-web-page")
	String getPersoWebPage();

	@Property("isASFMember")
	void setASFMember(boolean b);

	@Property("isASFMember")
	boolean isASFMember();
	
	@Property("isASEmeritusFMember")
	void setASFEmerituusMember(boolean b);

	@Property("isASFEmeritusMember")
	boolean isASFEmeritusMember();

	@Property("first-commit-date")
	void setFirstCommitDate(long date);

	@Property("first-commit-date")
	long getFirstCommitDate();

	@Property("latest-commit-date")
	void setLatestCommitDate(long date);

	@Property("latest-commit-date")
	long getLatestCommitDate();

	@Property("lines-added")
	void setLinesAdded(long lines);

	@Property("lines-added")
	long getLinesAdded();

	@Property("lines-removed")
	void setLinesRemoved(long lines);

	@Property("lines-removed")
	long getLinesRemoved();

	@Property("lines-modified")
	void setLinesModified(long lines);

	@Property("lines-modified")
	long getLinesModified();

	@Property("average-lines-per-commit")
	void setAverageLinesPerCommit(long lines);

	@Property("average-lines-per-commit")
	long getAverageLinesPerCommit();

	@Property("number-of-files-touched")
	void setNumberOfFilesTouched(int files);

	@Property("number-of-files-touched")
	int getNumberOfFilesTouched();

	@Property("number-of-files-changes")
	void setNumberOfFilesChanges(long changes);

	@Property("number-of-files-changes")
	long getNumberOfFilesChanges();

	@Property("unique-file-count")
	void setUniqueFileCount(int count);

	@Property("unique-file-count")
	int getUniqueFileCount();

	@Property("percent-file-unique")
	void setPercentFileUnique(double percent);

	@Property("percent-file-unique")
	double getPercentFileUnique();

	// TODO - Adjacency to Commit
	@Adjacency(label = PropagateRelation.PROPAGATE, direction = Direction.OUT)
	Iterable<Commit> getCommits();

	@Adjacency(label = PropagateRelation.PROPAGATE, direction = Direction.OUT)
	void addCommit(Commit c);

	@Adjacency(label = PropagateRelation.PROPAGATE, direction = Direction.OUT)
	void addCommits(Iterable<Commit> commits);

	// TODO - Adjacency to File
	@Adjacency(label = TouchRelation.TOUCH, direction = Direction.OUT)
	Iterable<File> getFiles();

	@Adjacency(label = TouchRelation.TOUCH, direction = Direction.OUT)
	void addFile(File f);

	@Adjacency(label = TouchRelation.TOUCH, direction = Direction.OUT)
	void addFiles(Iterable<File> files);

	// TODO - Self Adjacency to (Co) Committer
	@Adjacency(label = CoCommitterRelation.CO_COMMITTER, direction = Direction.OUT)
	Iterable<Committer> getCoCommitters();

	@Adjacency(label = CoCommitterRelation.CO_COMMITTER, direction = Direction.OUT)
	void addCoCommitter(Committer c);

	@Adjacency(label = CoCommitterRelation.CO_COMMITTER, direction = Direction.OUT)
	void addCoCommitters(Iterable<Committer> committers);

	// TODO - Adjacency to Same Project As
	@Adjacency(label = SameProjectAsRelation.SAME_PROJECT_AS, direction = Direction.OUT)
	Iterable<Committer> getSameProjectAs();

	@Adjacency(label = SameProjectAsRelation.SAME_PROJECT_AS, direction = Direction.OUT)
	void addSameProjectAs(Committer c);

	@Adjacency(label = SameProjectAsRelation.SAME_PROJECT_AS, direction = Direction.OUT)
	void addSameProjectAs(Iterable<Committer> committers);

	// TODO Adjacency to Forked Repository
	@Adjacency(label = ForkRelation.FORK, direction = Direction.OUT)
	Iterable<Repository> getForkedRepositories();

	@Adjacency(label = ForkRelation.FORK, direction = Direction.OUT)
	void addForkedRepository(Repository r);

	@Adjacency(label = ForkRelation.FORK, direction = Direction.OUT)
	void addForkedRepositories(Iterable<Repository> repositories);

	// TODO Adjacency to Registered_In Repository
	@Adjacency(label = RegisteredInRelation.REGISTERED_IN, direction = Direction.OUT)
	Iterable<Repository> getRegisteredInRepositories();

	@Adjacency(label = RegisteredInRelation.REGISTERED_IN, direction = Direction.OUT)
	void addRegisteredInRepository(Repository r);

	@Adjacency(label = RegisteredInRelation.REGISTERED_IN, direction = Direction.OUT)
	void addRegisteredInRepositories(Iterable<Repository> repositories);

	// TODO Adjacency to Project
	@Adjacency(label = HoldAdminRoleRelation.HOLD_ADMIN_ROLE, direction = Direction.OUT)
	Iterable<Project> getProjects();

	@Adjacency(label = HoldAdminRoleRelation.HOLD_ADMIN_ROLE, direction = Direction.OUT)
	void addProject(Project p);

	@Adjacency(label = HoldAdminRoleRelation.HOLD_ADMIN_ROLE, direction = Direction.OUT)
	void addProject(Iterable<Project> projects);

	// TODO Adjacency from Project
	@Adjacency(label = InvolveRelation.INVOLVE, direction = Direction.IN)
	Iterable<Project> getInvolvedInProjects();

	// TODO - Define Incidence if necessary

	// TODO - Derived Properties or Metrics, using Gremlin.

	/**
	 * Number of Commits.
	 * 
	 * @return the number of commits for this committer
	 */
	@GremlinGroovy(value = "it.outE('label', '" + PropagateRelation.PROPAGATE
			+ "').inV.gather{it.size()}", frame = false)
	Integer getNumberOfCommits();

	/**
	 * Total number of lines added by this committer.
	 * @return the number of lines added by this committer
	 */
	@GremlinGroovy(value = "x=0; it.outE('label', '"
			+ PropagateRelation.PROPAGATE + "').inV.outE.('" + AddRelation.ADD
			+ "', '" + ModifyRelation.MODIFY + "', '" + ReplaceRelation.REPLACE
			+ "').sideEffect{x+=it.getProperty('lines-added')}", frame = false)
	Integer getNumberOfLinesAdded();

}
